﻿
// Cobot_PrintServerDlg.cpp: 实现文件
//

#include "pch.h"
#include "framework.h"

#include "Cobot_PrintServer.h"
#include "Cobot_PrintServerDlg.h"

#include "TestAPI.h"
#include "./json/JSON.h"

#include "PrinterImpl.h"

#include "JsonServer.h"

#include "afxdialogex.h"

#include <boost/format.hpp>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define  DEFAULTWINDOW_X  1280               // 默认屏幕分辨率为1280* 800
#define  DEFANLTWINDOW_Y  800

httplib::Server svr;                        // 打印服务器;
std::string NetIP;                          // 打印机IP地址;
int printStatus[8];                         // 打印机状态;

HANDLE               g_mutex_detector;

CCobotPrintServerDlg* g_CobotPrintServerDlg = NULL;

#pragma comment(lib,"json_vc71_libmt.lib")

void ShowMedicineBoxId(UCHAR* medicineCode,int deviceType)
{
	assert(g_CobotPrintServerDlg != NULL);
	if (deviceType == 0)
	{
		std::string id((char*)medicineCode, 1, 10);

		int ret = JsonServer::getInstance()->findMedicineBoxIdFromMap(id);
		if (ret < 0)
		{
			g_CobotPrintServerDlg->m_serverDlg.showServerInfo("当前药框未绑定!\r\n");
		}
		else
		{
			g_CobotPrintServerDlg->sendMedicineBoxIdToServer(ret);
		}
	}
	else if (deviceType == 1)
	{
		std::string id((char*)medicineCode, 0, 9);

		int ret = JsonServer::getInstance()->findMedicineBoxIdFromMap(id);
		if (ret < 0)
		{
			g_CobotPrintServerDlg->m_serverDlg.showServerInfo("当前药框未绑定!\r\n");
		}
		else
		{
			g_CobotPrintServerDlg->sendMedicineBoxIdToServer(ret);
		}
	}
}


// UTF-8 转换成 unicode 字符;
char* UTF8toUnicode(char* szU8)
{
	//UTF8 to Unicode
   //预转换，得到所需空间的大小
	int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL, 0);
	//分配空间要给'\0'留个空间，MultiByteToWideChar不会给'\0'空间
	wchar_t* wszString = new wchar_t[wcsLen + 1];
	//转换
	::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen);
	//最后加上'\0'
	wszString[wcsLen] = '\0';

	char* m_char;
	int len = WideCharToMultiByte(CP_ACP, 0, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
	m_char = new char[len + 1];
	WideCharToMultiByte(CP_ACP, 0, wszString, wcslen(wszString), m_char, len, NULL, NULL);

	m_char[len] = '\0';
	return m_char;
}

std::string GBKToUTF8(const std::string & strGBK)
{
	std:: string strOutUTF8 = "";
	WCHAR* str1;
	int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);

	str1 = new WCHAR[n];
	MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);

	n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
	char* str2 = new char[n];

	WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
	strOutUTF8 = str2;

	delete[] str1;
	str1 = NULL;

	delete[] str2;
	str2 = NULL;

	return strOutUTF8;
}

// 日志系统;
void d_printf(const char* format, ...)
{
	static FILE* fp = NULL;

	if (fp == NULL)
	{
		fp = fopen("print_log.txt", "w");
	}
	va_list ap;

	SYSTEMTIME tv;
	GetLocalTime(&tv);

	WaitForSingleObject(g_mutex_detector, INFINITE);

	long loffset = ftell(fp);

	if (loffset > 10000000)// 大于10M 从文件头开始再写;
	{
		fseek(fp, 0, SEEK_SET);
	}

	fprintf(fp, "%04d-%02d-%02d %02d:%02d:%02d  ",(int)tv.wYear,(int)tv.wMonth,(int)tv.wDay,(int)tv.wHour, tv.wMinute, tv.wSecond);

	va_start(ap, format);

	vfprintf(fp, format, ap);

	fflush(fp);
	va_end(ap);

	ReleaseMutex(g_mutex_detector);
}

DWORD WINAPI thread_http_server(void* ptr)
{	
	// 服务器启动;
	CCobotPrintServerDlg* dlg = (CCobotPrintServerDlg*)(ptr);
	assert(dlg != NULL);

	svr.listen("0.0.0.0", dlg->port);
	
	return true;
}

DWORD WINAPI QueryPrinterStatus(void* ptr)
{	
	CCobotPrintServerDlg* dlg = (CCobotPrintServerDlg*)(ptr);
	assert(dlg != NULL);
	bool onlyOnce = false;
	bool exceptionExist = false;
	memset(printStatus, 0, sizeof(int) * 8);
	while (dlg->queryPrinterStatusStart)
	{	
		int ret = PrinterImpl::getInstance()->queryStatus(printStatus);

		if (ret == -1)
		{
			// 打印机连接异常; 
			onlyOnce = false;
			exceptionExist = true;
			dlg->PostMessageToServerWindow(printStatus::Exception);
		}
		else if (ret == 0)
		{
			if (exceptionExist)
			{
				int ret = PrinterImpl::getInstance()->openPrinter(NetIP);
				if (ret == 0)
				{
					exceptionExist = false;
				}
			}
			if (onlyOnce == false)
			{
				// 一切正常;
				dlg->PostMessageToServerWindow(printStatus::OK);
				onlyOnce = true;
			}
		}
		else
		{	
			onlyOnce = false;
			if (printStatus[0] == 0)
			{	
				//有钱箱打开;
				dlg->PostMessageToServerWindow(printStatus::cashOpen);
			}

			if (printStatus[1] == 1)
			{	
				//打印机脱机;
				dlg->PostMessageToServerWindow(printStatus::Offline);
			}

			if (printStatus[2] == 1)
			{	
				//上盖打开;
				dlg->PostMessageToServerWindow(printStatus::coverOpen);
			}

			//if (status[3] == 1)
			//{	
			//	//正在进纸;	
			//	dlg->PostMessageToServerWindow(printStatus::);
			//}

			if (printStatus[4] == 1)
			{
				//打印机出错;
				dlg->PostMessageToServerWindow(printStatus::Error);
			}

			if (printStatus[5] == 1)
			{	
				//切刀出错;
				dlg->PostMessageToServerWindow(printStatus::cutterError);
			}

			if (printStatus[6] == 1)
			{	
				// 纸将尽;
				dlg->PostMessageToServerWindow(printStatus::paperNearEnd);
			}

			if (printStatus[7] == 1)
			{
				//缺纸;
				dlg->PostMessageToServerWindow(printStatus::paperEnd);
			}
		}
		Sleep(1000);
	}

	d_printf("QueryPrinterStatus 线程结束\r\n");
	return 0;
}

DWORD WINAPI GetRecipeTaskInfoThread(void* ptr)
{	
	CCobotPrintServerDlg* dlg = (CCobotPrintServerDlg*)(ptr);
	assert(dlg != NULL);
	while (dlg->getRecipeTaskInfoStart)
	{	
		dlg->getRecipeTaskInfo();
		Sleep(1000*10);
	}
	return 0;
}

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{

}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CCobotPrintServerDlg 对话框



CCobotPrintServerDlg::CCobotPrintServerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_COBOT_PRINTSERVER_DIALOG, pParent) //IDD_COBOT_PRINTSERVER_DIALOG
{	
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	queryPrinterStatusStart = false;
	getRecipeTaskInfoStart = false;
	isRFIDComOpen = false;
	port = 8080;
}

void CCobotPrintServerDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TAB_MAIN, m_ctrTab);
}

BEGIN_MESSAGE_MAP(CCobotPrintServerDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	ON_COMMAND(ID_START, &CCobotPrintServerDlg::OnStart)
	ON_UPDATE_COMMAND_UI(ID_START, &CCobotPrintServerDlg::OnUpdateStart)
	ON_WM_INITMENUPOPUP()
	ON_COMMAND(ID_STOP, &CCobotPrintServerDlg::OnStop)
	ON_UPDATE_COMMAND_UI(ID_STOP, &CCobotPrintServerDlg::OnUpdateStop)
	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB_MAIN, &CCobotPrintServerDlg::OnTcnSelchangeTabMain)
	ON_COMMAND(ID_PARAM_SET, &CCobotPrintServerDlg::OnParamSet)
	ON_WM_SIZE()
	ON_COMMAND(ID_RFID_START, &CCobotPrintServerDlg::OnRFIDStart)
	ON_UPDATE_COMMAND_UI(ID_RFID_START, &CCobotPrintServerDlg::OnUpdateRFIDStart)
	ON_COMMAND(ID_RFID_STOP, &CCobotPrintServerDlg::OnRFIDStop)
	ON_UPDATE_COMMAND_UI(ID_RFID_STOP, &CCobotPrintServerDlg::OnUpdateRFIDStop)
	ON_COMMAND(ID_LOAD_MEDBOX, &CCobotPrintServerDlg::OnLoadMedbox)
END_MESSAGE_MAP()



// CCobotPrintServerDlg 消息处理程序

BOOL CCobotPrintServerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != nullptr)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	g_CobotPrintServerDlg = this;

	// 默认尺寸是800 600
	int  x = GetSystemMetrics(SM_CXSCREEN);
	int  y = GetSystemMetrics(SM_CYSCREEN);
	//int x = 800;
	//int y = 600;
	if (x == DEFAULTWINDOW_X && y == DEFANLTWINDOW_Y)
	{
		d_printf("屏幕分辨率 = %d,%d", x, y);
		CRect rc(0, 0, x-1, y-1);
		MoveWindow(rc, true);

		GetClientRect(&m_rect);
	}
	else
	{
		x = x * 2 / 3;
		y = y * 2 / 3;
		// 居中;
		CRect rc(0, 0, x, y);
		MoveWindow(rc, true);

		GetClientRect(&m_rect);
	}
	
	CenterWindow();

	init();

	m_serverDlg.showServerInfo("服务初始化完成，请启动服务器\r\n");
	svr.set_error_handler([](const httplib::Request& /*req*/, httplib::Response& res) {
		const char* fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
		char buf[BUFSIZ];
		snprintf(buf, sizeof(buf), fmt, res.status);
		res.set_content(buf, "text/html");
		d_printf(fmt);
		});

	// 显示当前处方信息;
	svr.Post("/showlist", [this](const httplib::Request& req, httplib::Response& res) {
		this->showRecipeList(req,res);
		});


	svr.Post("/show", [this](const httplib::Request& req, httplib::Response& res) {	
		this->showCurRecipeInfo(req,res);
		});

	// 打印;
	svr.Post("/print", [this](const httplib::Request & req, httplib::Response& res) {
		this->printCurRecipeInfo(req, res);
		});

	// 打印缺药清单;
	svr.Post("/printShortDrugList", [this](const httplib::Request& req, httplib::Response& res) {
		this->printShortDrugList(req, res);
		});

	svr.Get("/printStatus", [this](const httplib::Request& req, httplib::Response& res) {
		this->sendPrintStatusToDev(req,res);
		});

	return TRUE;                     // 除非将焦点设置到控件，否则返回 TRUE
}

void CCobotPrintServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CCobotPrintServerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CCobotPrintServerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CCobotPrintServerDlg::OnStart()
{
	// TODO: 在此添加命令处理程序代码
	//1.连接打印机;
	int result = PrinterImpl::getInstance()->openPrinter(NetIP);
	if (result == -1)
	{
		m_serverDlg.showServerInfo("打印机连接异常\r\n");
		return;
	}

	// 2 创建监听打印机线程
	queryPrinterStatusStart = true;
	DWORD threadId;
	CreateThread(0, 0, QueryPrinterStatus, this, 0, &threadId);

	m_serverDlg.showServerInfo("打印机连接成功\r\n");

	// 3 创建HTTP server监听线程;
	CreateThread(0, 0, thread_http_server, this, 0, &threadId);	

	// 4 创建http client 获取药房管理系统处方信息;
	httpClient = boost::make_shared<httplib::Client>(remoteIP, port);

	// 5 创建线程，从药房管理系统读取处方信息;
	getRecipeTaskInfoStart = true;
	CreateThread(0, 0, GetRecipeTaskInfoThread, this, 0, &threadId);

	m_serverDlg.showServerInfo("打印服务器启动\r\n");
}


void CCobotPrintServerDlg::OnUpdateStart(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->Enable(!svr.is_running());
}


void CCobotPrintServerDlg::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)
{
	CDialogEx::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);

	// TODO: 在此处添加消息处理程序代码
	ASSERT(pPopupMenu != NULL);
	// Check the enabled state of various menu items.
	CCmdUI state;
	state.m_pMenu = pPopupMenu;
	ASSERT(state.m_pOther == NULL);
	ASSERT(state.m_pParentMenu == NULL);
	// Determine if menu is popup in top-level menu and set m_pOther to
	// it if so (m_pParentMenu == NULL indicates that it is secondary popup).
	HMENU hParentMenu;
	if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)
		state.m_pParentMenu = pPopupMenu;    // Parent == child for tracking popup.
	else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)
	{
		CWnd* pParent = this;
		// Child windows don't have menus--need to go to the top!
		if (pParent != NULL &
			(hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)
		{
			int nIndexMax = ::GetMenuItemCount(hParentMenu);
			for (int nIndex = 0; nIndex < nIndexMax; nIndex++)
			{
				if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)
				{
					// When popup is found, m_pParentMenu is containing menu.
					state.m_pParentMenu = CMenu::FromHandle(hParentMenu);
					break;
				}
			}
		}
	}
	state.m_nIndexMax = pPopupMenu->GetMenuItemCount();
	for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
		state.m_nIndex++)
	{
		state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);
		if (state.m_nID == 0)
			continue; // Menu separator or invalid cmd - ignore it.
		ASSERT(state.m_pOther == NULL);
		ASSERT(state.m_pMenu != NULL);
		if (state.m_nID == (UINT)-1)
		{
			// Possibly a popup menu, route to first item of that popup.
			state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);
			if (state.m_pSubMenu == NULL ||
				(state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||
				state.m_nID == (UINT)-1)
			{
				continue;       // First item of popup can't be routed to.
			}
			state.DoUpdate(this, TRUE);   // Popups are never auto disabled.
		}
		else
		{
			// Normal menu item.
			// Auto enable/disable if frame window has m_bAutoMenuEnable
			// set and command is _not_ a system command.
			state.m_pSubMenu = NULL;
			state.DoUpdate(this, FALSE);
		}
		// Adjust for menu deletions and additions.
		UINT nCount = pPopupMenu->GetMenuItemCount();
		if (nCount < state.m_nIndexMax)
		{
			state.m_nIndex -= (state.m_nIndexMax - nCount);
			while (state.m_nIndex < nCount &
				pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)
			{
				state.m_nIndex++;
			}
		}
		state.m_nIndexMax = nCount;
	}
}


void CCobotPrintServerDlg::OnStop()
{
	// TODO: 在此添加命令处理程序代码

	// 停止服务器;
	if (svr.is_running())
	{
		svr.stop();
	}
	httpClient->stop();


	m_serverDlg.showServerInfo("打印服务结束\r\n");

	queryPrinterStatusStart = false;
	getRecipeTaskInfoStart = false;

	Sleep(10);
	// 停止打印机;
	int result = PrinterImpl::getInstance()->closePrinter();
	if (result == 0)
	{
		m_serverDlg.showServerInfo("打印机端口关闭成功\r\n");
	}
	else
	{
		m_serverDlg.showServerInfo("打印机端口关闭异常\r\n");
	}
}


void CCobotPrintServerDlg::OnUpdateStop(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->Enable(svr.is_running());
}

void CCobotPrintServerDlg::OnInitTab()
{
	// 向标签控件中添加选项卡;
	TCITEM item;
	item.mask = TCIF_TEXT;
	item.pszText = "配药单"; // 打印详情
	m_ctrTab.InsertItem(0,&item);
	
	item.pszText = "日志";
	m_ctrTab.InsertItem(1,&item);

	// 创建标签页窗口;
	m_serverDlg.Create(IDD_DLG_SERVER,&m_ctrTab);
	m_recipeDlg.Create(IDD_DLG_REPICE,&m_ctrTab);

	CRect rect;
	m_ctrTab.GetClientRect(&rect);
	rect.top += 30;
	rect.bottom -= 4;
	rect.left += 4;
	rect.right -= 4;
	
	// 移动子窗口;
	m_serverDlg.MoveWindow(&rect);
	m_recipeDlg.MoveWindow(&rect);
	
	m_serverDlg.ShowWindow(SW_SHOW);
	m_recipeDlg.ShowWindow(SW_HIDE);

	m_ctrTab.SetCurSel(0);		// 设置默认选中的标签页;
	SelectTabPage();		    // 显示子窗口;
}

void CCobotPrintServerDlg::SelectTabPage()
{
	int nCurSel = m_ctrTab.GetCurSel();
	switch (nCurSel)
	{
		case 0:
		{
			m_serverDlg.ShowWindow(SW_SHOW);
			m_recipeDlg.ShowWindow(SW_HIDE);
			break;
		}
		
		case 1:
		{
			m_serverDlg.ShowWindow(SW_HIDE);
			m_recipeDlg.ShowWindow(SW_SHOW);
			break;
		}

	default:
		break;
	}
}

void CCobotPrintServerDlg::PostMessageToRecipeWindow()
{
	// 发送消息，处方窗口去刷新界面;
	::PostMessage(m_recipeDlg.m_hWnd,WM_UPDATE_WINDOW_RECIPE,0,0);
}

void CCobotPrintServerDlg::UpdateHistoryRecipeMessage()
{
	::PostMessage(m_recipeDlg.m_hWnd, WM_UPDATE_HISTORY_RECIPE, 0, 0);
}

void CCobotPrintServerDlg::PostMessageToServerWindow(int status)
{
	::PostMessage(m_serverDlg.m_hWnd, WM_UPDATE_PRINT_STATUS, 0, LPARAM(status));
}

void CCobotPrintServerDlg::ResetRecipeWindowMessage()
{
	::PostMessage(m_recipeDlg.m_hWnd, WM_RESET_RECIPE_WINDOW, 0, 0);
}

void CCobotPrintServerDlg::UpdateRecipeNumMessage(int all, int finish, int pending)
{	
	SRecipeNumInfo* pa = new SRecipeNumInfo();
	pa->recipeAll = all;
	pa->recipeProcessed = finish;
	pa->recipePending = pending;
	::PostMessage(m_serverDlg.m_hWnd, WM_UPDATE_RECIPE_NUM, (WPARAM)pa,0);
}

void CCobotPrintServerDlg::UpdateMedicineBoxIdMessage(int medicineNum)
{	
	::PostMessage(m_serverDlg.m_hWnd, WM_UPDATE_MEDICINE_BOXID, 0, LPARAM(medicineNum));
}

void CCobotPrintServerDlg::OnTcnSelchangeTabMain(NMHDR* pNMHDR, LRESULT* pResult)
{
	// TODO: 在此添加控件通知处理程序代码
	SelectTabPage();
	*pResult = 0;
}


void CCobotPrintServerDlg::OnParamSet()
{
	// 配置打印机IP地址，已经历史记录保存等相关信息;
}


bool CCobotPrintServerDlg::init()
{	
	m_Menu.LoadMenu(IDR_MENU1);
	SetMenu(&m_Menu);
	
	skinppLoadSkin(_T("MSN Messenger.ssk"));
	OnInitTab();

	SetTimer(TIMER1, 1000, NULL);         // 清空数据定时器;
	
	m_serverDlg.showServerInfo("正在初始化服务......\r\n");
	
	m_serverDlg.showServerInfo("加载处方信息......\r\n");
	
	loadMedicineBoxInfo();
	loadRecipeAndPrintInfo();

	UpdateHistoryRecipeMessage();

	g_mutex_detector = CreateMutex(
		NULL,              // default security attributes
		FALSE,             // initially not owned
		NULL);             // unnamed mutex

	// svr bind 打印相关接口;
	if (!svr.is_valid())
	{
		m_serverDlg.showServerInfo("服务初始化失败\r\n");
		return false;
	}


	// 加载打印机API驱动;
	int result;
	result = PrinterImpl::getInstance()->init();
	
	if (result == -1)
	{
		m_serverDlg.showServerInfo("打印机驱动加载失败,请检查是否更新驱动程序\r\n");
		return false;
	}

	if (!JsonServer::getInstance()->readJsonParamFile(NetIP))
	{
		m_serverDlg.showServerInfo("param.json配置文件加载失败\r\n");
		return false;
	}

	remoteIP = JsonServer::getInstance()->getServerIP();
	port = JsonServer::getInstance()->getPort();

	m_serverDlg.updatePrinterIP(NetIP);
	
	return true;
}

void CCobotPrintServerDlg::loadRecipeAndPrintInfo()
{	
	// 检验recipe.json 和 print.json文件是否是当天，由于两个文件都是同时处理，所以检测一个即可;
	if (JsonServer::getInstance()->checkJsonFileDate())
	{	
		// load recipe.json;
		if (!JsonServer::getInstance()->readRecipeInfoFromFile())
		{
			m_serverDlg.showServerInfo("加载recipe.json文件出错\r\n");
			return;
		}

		// load print.json;
		if (!JsonServer::getInstance()->readPrintInfoFromFile())
		{
			m_serverDlg.showServerInfo("加载print.json文件出错\r\n");
			return;
		}

		m_serverDlg.showServerInfo("加载recipe.json print.json文件完成\r\n");	
	}
}

void CCobotPrintServerDlg::loadMedicineBoxInfo()
{
	if (!JsonServer::getInstance()->readMedicineBoxInfoFromFile())
	{
		m_serverDlg.showServerInfo("加载medicineBox.json文件出错\r\n");
		return;
	}
	m_serverDlg.showServerInfo("加载medicineBox.json文件完成\r\n");
}

void CCobotPrintServerDlg::sendMedicineBoxIdToServer(int id)
{	
	if (isRFIDComOpen)
	{
		std::string jsonString;
		JsonServer::getInstance()->makeJsonString(id, jsonString);
		if (auto  res = httpClient_MedicineBox->Post("/api/MedicineBox/PushNewMedicalBox", jsonString, "application/json"))
		{
			if (res->status == 200)
			{
				std::string info = "绑定成功，药框编号: " + std::to_string(id);
				info += "\r\n";
				m_serverDlg.showServerInfo(info);
			}
		}
		else
		{
			m_serverDlg.showServerInfo("绑定失败\r\n");
		}
	}
}

void CCobotPrintServerDlg::showRecipeList(const httplib::Request& req, httplib::Response& res)
{
	//所有处方列表;
	//RecipeDrugInfoSet drugInfoList;
	std::string body = UTF8toUnicode((char*)req.body.c_str());
	//Puppy::Common::JSON::parseJSON(body, drugInfoList);

	//m_jsonServer.SetRecipeID(drugInfoList.recipeId);

	//(this->m_serverDlg).showRecipeInfoList(drugInfoList);	  // 数据解析后，传给CServerDlg显示;
	res.set_content("show finish!\n", "text/plain");
}

void CCobotPrintServerDlg::showCurRecipeInfo(const httplib::Request& req, httplib::Response& res)
{	
	//1. 查询打印机状态，给药房管理系统通知打印机状态; todo...
	if (printStatus[1] == 1 || printStatus[2] == 1 || printStatus[4] == 1 || printStatus[5] == 1)
	{
		res.set_content("0\n", "text/plain");  // 异常;
		return;
	}

	if (printStatus[6] == 1 || printStatus[7] == 1)
	{	
		res.set_content("1\n", "text/plain");    //纸将尽;
		return;
	}

	res.set_content("2\n", "text/plain");       //正常;

	RecipeDrugInfoSet drugInfoList;
	std::string body = UTF8toUnicode((char*)req.body.c_str());
	Puppy::Common::JSON::parseJSON(body, drugInfoList);

	boost::format f = boost::format("正在打印当前配药单..., 当前病人ID: % s\r\n")% drugInfoList.patientId;
	
	m_serverDlg.showServerInfo(f.str());

	JsonServer::getInstance()->addRecipeInfoToMap(drugInfoList.patientId, drugInfoList.uniqueId, body);   // 当前处方信息加载到容器中;

	PostMessageToRecipeWindow();                                                  //更新配药单历史记录;

	m_serverDlg.showRecipeInfoList(drugInfoList);	                              // 数据解析后，传给CServerDlg显示;
}

void CCobotPrintServerDlg::printCurRecipeInfo(const httplib::Request& req, httplib::Response& res)
{	
	std::string body = UTF8toUnicode((char*)req.body.c_str());
	int ret = JsonServer::getInstance()->addPrintInfoToMap(body);
	if (ret < 0)
	{	
		m_serverDlg.showServerInfo("解析处方打印信息错误\r\n");
		return;
	}
	
	res.set_content("print finish!\n", "text/plain");

	PrinterImpl::getInstance()->print(body);

	m_serverDlg.showServerInfo("当前处方打印完成\r\n");
}

void CCobotPrintServerDlg::printShortDrugList(const httplib::Request& req, httplib::Response& res)
{	
	//std::string GBKToUTF8(const std::string & strGBK)
	std::string tem = GBKToUTF8(req.body);
	std::string body = UTF8toUnicode((char*)tem.c_str());

	//std::string body = UTF8toUnicode((char*)req.body.c_str());
	PrinterImpl::getInstance()->printShortMedicineList(body);
	res.set_content("print finish!\n", "text/plain");

	m_serverDlg.showServerInfo("打印发药机缺药清单\r\n");
}

void CCobotPrintServerDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: 在此处添加消息处理程序代码
}

void CCobotPrintServerDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	switch (nIDEvent)
	{
		case TIMER1:
		{
			CTime tm;
			tm = CTime::GetCurrentTime();
			// 每天晚上23:00:00 清空本地数据和文件;
			if (tm.GetHour() == 23 && tm.GetMinute() == 0 && tm.GetSecond() == 0)
			{	
				m_serverDlg.showServerInfo("夜间时间:23:00:00 清空当日数据\r\n");
				d_printf("Time:[23:00:00] clear all\n");
				// 界面刷新;
				ResetRecipeWindowMessage();
				JsonServer::getInstance()->clearAllData();
			}
			break;
		}
	}
	
	CDialogEx::OnTimer(nIDEvent);
}

void CCobotPrintServerDlg::getRecipeTaskInfo()
{
	// 获取当前处方详情;
	d_printf("getRecipeTaskInfo start\n");
	if (auto res = httpClient->Get("/api/DispenseTask/GetDispenseTaskAll"))  // http://192.168.20.63:8080/api/Values/Get
	{
		std::string body = UTF8toUnicode((char*)res->body.c_str());
		int taskTotal, taskFinish, taskPending;
		JsonServer::getInstance()->parseRecipeTaskNumInfo(body, taskTotal, taskFinish, taskPending);
		UpdateRecipeNumMessage(taskTotal, taskFinish, taskPending);
		d_printf("GetDispenseTaskAll taskTotal =  %d, taskFinish = %d, taskPending = %d\n", taskTotal, taskFinish, taskPending);
	}
	else
	{	
		d_printf("getRecipeTaskInfo fail\n");
	}
}

void CCobotPrintServerDlg::sendPrintStatusToDev(const httplib::Request& req, httplib::Response& res)
{
	if (printStatus[1] == 1 || printStatus[2] == 1 || printStatus[4] == 1 || printStatus[5] == 1)
	{
		res.set_content("0", "text/plain"); // 0 error
		return;
	}

	if (printStatus[6] == 1 || printStatus[7] == 1)
	{
		res.set_content("1", "text/plain");// 纸将尽;
		return;
	}
	res.set_content("2", "text/plain");   //  打印机正常;
}


BOOL CCobotPrintServerDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	if (pMsg->message == WM_KEYDOWN)
	{
		switch (pMsg->wParam)
		{
		case VK_RETURN: // 屏蔽回车
			return TRUE;
		case VK_ESCAPE:
			return TRUE;
		}
	}
	return CDialogEx::PreTranslateMessage(pMsg);
}

void CCobotPrintServerDlg::ChangeSize(UINT nID, int x, int y)
{
	CWnd* pWnd;
	pWnd = GetDlgItem(nID);
	if (pWnd != NULL) //判断是否为空，因为在窗口创建的时候也会调用OnSize函数，但是此时各个控件还没有创建，Pwnd为空
	{
		CRect rec;
		pWnd->GetWindowRect(&rec); //获取控件变化前的大小
		ScreenToClient(&rec); //将控件大小装换位在对话框中的区域坐标
		rec.left = rec.left * x / m_rect.Width(); //按照比例调整空间的新位置
		rec.top = rec.top * y / m_rect.Height();
		rec.bottom = rec.bottom * y / m_rect.Height();
		rec.right = rec.right * x / m_rect.Width();
		pWnd->MoveWindow(rec); //伸缩控件
	}
}

void CCobotPrintServerDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialogEx::OnSize(nType, cx, cy);

	// TODO: 在此处添加消息处理程序代码
	if (nType != SIZE_MINIMIZED) //判断窗口是不是最小化了，因为窗口最小化之后 ，窗口的长和宽会变成0，当前一次变化的时就会出现除以0的错误操作
	{
		if (cy > 10000)
		{
			return;
		}
		ChangeSize(IDC_TAB_MAIN, cx, cy); //对每一个控件依次做调整

		//修改tab control中的子界面 
		CRect rectPara1;
		m_ctrTab.GetClientRect(&rectPara1);
		//调整子对话框在父窗口中的位置 
		rectPara1.top += 20;
		rectPara1.bottom += 4;
		rectPara1.left += 4;
		rectPara1.right -= 4;
		m_serverDlg.MoveWindow(rectPara1);
		m_recipeDlg.MoveWindow(rectPara1);

		GetClientRect(&m_rect); //最后要更新对话框的大小，当做下一次变化的旧坐标	
	}
}

void CCobotPrintServerDlg::OnRFIDStart()
{
	// TODO: 在此添加命令处理程序代码
	
	// 打开串口，读取RFID卡号; //提供一个回调函数，当读取卡号后，回调;
	comRFID = JsonServer::getInstance()->getRFIDCom();
	int port = JsonServer::getInstance()->getMedicineBoxServicePort();
	int ret = m_RFIDRead.openRFID(comRFID, ShowMedicineBoxId);
	if (ret < 0)
	{	
		isRFIDComOpen = false;
		m_serverDlg.showServerInfo("RFID串口打开失败，请检查设备\r\n");
	}
	else
	{	
		httpClient_MedicineBox = boost::make_shared<httplib::Client>(remoteIP, port);

		isRFIDComOpen = true;
		m_serverDlg.showServerInfo("RFID串口打开成功\r\n");
	}
}


void CCobotPrintServerDlg::OnUpdateRFIDStart(CCmdUI* pCmdUI)
{	
	pCmdUI->Enable(!isRFIDComOpen);
	// TODO: 在此添加命令更新用户界面处理程序代码
}

void CCobotPrintServerDlg::OnRFIDStop()
{
	// TODO: 在此添加命令处理程序代码
	isRFIDComOpen = false;
	m_RFIDRead.closeRFID();
	httpClient_MedicineBox->stop();
	m_serverDlg.showServerInfo("RFID串口关闭\r\n");
}

void CCobotPrintServerDlg::OnUpdateRFIDStop(CCmdUI* pCmdUI)
{
	// TODO: 在此添加命令更新用户界面处理程序代码
	pCmdUI->Enable(isRFIDComOpen);
}

void CCobotPrintServerDlg::OnLoadMedbox()
{
	// TODO: 在此添加命令处理程序代码
	loadMedicineBoxInfo();
}
